from pathlib import (
    Path as Path,
)



def init ():
    import platform
    from datetime import (datetime, timezone,)
    from shutil import (rmtree,)
    import sas4tool
    py_impl = platform.python_implementation().lower()
    py_ver = platform.python_version().lower()
    py_compiler = platform.python_compiler().lower().replace(' ', '_').replace('.', '_').replace('(', '').replace(')', '')
    py_arch = '-'.join(platform.architecture()).lower().replace(' ', '_')
    prog_out_filename = f'sas4tool-{py_impl}-{py_ver}-{py_compiler}-{py_arch}'
    prog_out_dir = Path( f'./dist/{prog_out_filename}/' )
    prog_build_dir = Path( f'./build/{prog_out_filename}/' )
    kwargs = {
        'prog_filename': 'sas4tool',
        'prog_author': sas4tool.__AUTHOR__,
        'prog_version': sas4tool.__VERSION__,
        'prog_desc': sas4tool.__doc__,
        'prog_timestamp': int(datetime.now(timezone.utc).timestamp()),
        'prog_out_filename': prog_out_filename,
        'prog_out_dir': prog_out_dir,
        'prog_build_dir': prog_build_dir,
        'cfg_config': Path('./.template/config.json'),
        'cfg_items': Path('./items.json'),
        'cfg_license': Path('./LICENSE'),
    }
    if prog_build_dir.exists():
        rmtree( prog_build_dir )
    prog_build_dir.mkdir( parents=True, exist_ok=True )
    prog_out_dir.mkdir( parents=True, exist_ok=True )
    return kwargs


def check_outpath (outdir, filename, ext=None):
    if ext:
        path = (Path(outdir) / f'{filename}{ext}')
    else:
        path = (Path(outdir) / filename)
        if not path.exists():
            path = (Path(outdir) / f'{filename}.dmg')
        if not path.exists():
            path = (Path(outdir) / f'{filename}.exe')
    path.resolve( strict=True )
    return path


def post (kwargs):
    from shutil import (copyfile,)
    cfg_config = kwargs['cfg_config']
    cfg_items = kwargs['cfg_items']
    cfg_license = kwargs['cfg_license']
    prog_out_dir = kwargs['prog_out_dir']
    copyfile( cfg_config, (prog_out_dir / cfg_config.name), follow_symlinks=False )
    copyfile( cfg_items, (prog_out_dir / cfg_items.name), follow_symlinks=False )
    copyfile( cfg_license, (prog_out_dir / cfg_license.name), follow_symlinks=False )


def build_nuitka ():
    import sys
    from subprocess import (run,)
    from pprint import (pprint)
    kwargs = init()
    build_dir = kwargs['prog_build_dir']
    filename = kwargs['prog_filename']
    prog_version = kwargs['prog_version']
    prog_desc = kwargs['prog_desc']
    prog_author = kwargs['prog_author']
    prog_out_dir = kwargs['prog_out_dir']
    # Build
    result = run([
        'poetry',
        'run',
        'nuitka',
        str(Path('./.template/sas4tool-standalone-stub.py')),
        #'--verbose',
        '--deployment',
        '--enable-console',
        '--onefile',
        '--msvc=14.1',
        f"--output-dir={build_dir}",
        f"--output-filename={filename}",
        #'--remove-output',
        '--full-compat',
        '--unstripped',
        '--no-pyi-file',
        '--lto=no',
        # Version Info
        f'--file-version={prog_version}',
        f'--product-version={prog_version}',
        '--product-name=SAS4Tool',
        f'--file-description={prog_desc}',
        f'--company-name="{prog_author}"',
        f'--copyright="{prog_author}"',
        f'--trademarks="{prog_author}"',
    ], shell=True, stdout=sys.stdout, stderr=sys.stderr, stdin=None,)
    pprint( result )
    output_path = check_outpath( build_dir, filename )
    target_path = (prog_out_dir / output_path.name)
    if target_path.exists():
        target_path.unlink( missing_ok=True )
    output_path = output_path.rename( (prog_out_dir / output_path.name) )
    check_outpath( prog_out_dir, filename )
    kwargs['prog_out_path'] = output_path
    post( kwargs )


def build_pyinstaller ():
    FIXEDFILEINFO = '''VSVersionInfo(
  ffi=FixedFileInfo(
    # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
    # Set not needed items to zero 0.
    filevers={version_tuple},
    prodvers={version_tuple},
    # Contains a bitmask that specifies the valid bits 'flags'r
    mask=0x3f,
    # Contains a bitmask that specifies the Boolean attributes of the file.
    flags=0x0,
    # The operating system for which this file was designed.
    # 0x4 - NT and there is no need to change it.
    OS=0x40004,
    # The general type of file.
    # 0x1 - the file is an application.
    fileType=0x1,
    # The function of the file.
    # 0x0 - the function is not defined for this fileType
    subtype=0x0,
    # Creation date and time stamp.
    date={date_tuple}
    ),
  kids=[
    StringFileInfo(
      [
      StringTable(
        '040904B0',
        [StringStruct('CompanyName', '{author}'),
        StringStruct('FileVersion', '{version}'),
        StringStruct('FileDescription', '{description}'),
        StringStruct('LegalCopyright', '{author}'),
        StringStruct('LegalTrademarks', '{author}'),
        StringStruct('InternalName', 'sas4tool-standalone-stub.py'),
        StringStruct('OriginalFilename', '{filename}.exe'),
        StringStruct('ProductName', 'SAS4Tool'),
        StringStruct('ProductVersion', '{version}'),
        StringStruct('Creator', '{author}')])
      ]),
    VarFileInfo([VarStruct('Translation', [1033, 1200])])
  ]
)'''
    from itertools import (chain, repeat, islice,)
    from PyInstaller.__main__ import (run,)
    kwargs = init()
    build_dir = kwargs['prog_build_dir']
    filename = kwargs['prog_filename']
    prog_version = kwargs['prog_version']
    prog_desc = kwargs['prog_desc']
    prog_author = kwargs['prog_author']
    prog_timestamp = kwargs['prog_timestamp']
    prog_out_dir = kwargs['prog_out_dir']
    # Version info file
    versioninfo_path = (build_dir / f'{filename}.versioninfo')
    versioninfo = FIXEDFILEINFO.format(
        filename=filename,
        version=prog_version,
        author=prog_author,
        description=prog_desc,
        version_tuple=tuple(islice(chain((int(x) for x in prog_version.split('.')), repeat(0)), 4)),
        date_tuple=(prog_timestamp, prog_timestamp,),
    )
    with versioninfo_path.open('w', encoding='utf8') as file:
        file.write( versioninfo )
    # Build
    run([
        './.template/sas4tool-standalone-stub.py',
        '--clean',
        '--console',
        '--onefile',
        '--noupx',
        f'--name={filename}',
        f'--workpath={build_dir}',
        f'--specpath={build_dir}',
        f'--version-file={versioninfo_path.name}',
        f'--distpath={prog_out_dir}',
    ])
    output_path = check_outpath( prog_out_dir, filename )
    kwargs['prog_out_path'] = output_path
    post( kwargs )


def build_py2exe ():
    from zipfile import (main as zipper,)
    from py2exe import (freeze,)
    kwargs = init()
    build_dir = kwargs['prog_build_dir']
    filename = kwargs['prog_filename']
    prog_version = kwargs['prog_version']
    prog_desc = kwargs['prog_desc']
    prog_author = kwargs['prog_author']
    prog_out_dir = kwargs['prog_out_dir']
    prog_out_filename = kwargs['prog_out_filename']
    # Build
    freeze(
        version_info={
            'product_name': 'SAS4Tool',
            'product_version': prog_version,
            'version': prog_version,
            'company_name': prog_author,
            'description': prog_desc,
            'internal_name': 'sas4tool-standalone-stub.py',
        },
        console=[
            {
                'script': './.template/sas4tool-standalone-stub.py',
                'dest_base': filename,
            },
        ],
        options={
            'verbose': 4,
            'dist_dir': build_dir,
        },
        data_files=[
            ('', [
                kwargs['cfg_config'],
                kwargs['cfg_items'],
                kwargs['cfg_license'],
            ]),
        ],
        zipfile=f'sas4tool.lib',
    )
    check_outpath( build_dir, filename )
    output_path = (prog_out_dir / f'{prog_out_filename}.zip')
    zipper( ['--create', f'{output_path}', f'{build_dir}',] )
    output_path = check_outpath( prog_out_dir, prog_out_filename, '.zip' )
    kwargs['prog_out_path'] = output_path


def build_cxfreeze ():
    from zipfile import (main as zipper,)
    from cx_Freeze.executable import (Executable,)
    from cx_Freeze.freezer import (Freezer,)
    kwargs = init()
    build_dir = kwargs['prog_build_dir']
    filename = kwargs['prog_filename']
    prog_version = kwargs['prog_version']
    prog_desc = kwargs['prog_desc']
    prog_author = kwargs['prog_author']
    prog_out_dir = kwargs['prog_out_dir']
    prog_out_filename = kwargs['prog_out_filename']
    # Build
    args = {
        'script': './.template/sas4tool-standalone-stub.py',
        'init_script': None,
        'base_name': None,
        'target_name': filename,
        'icon': None,
        'shortcut_name': None,
        'shortcut_dir': None,
        'copyright': prog_author,
        'trademarks': prog_author,
        'metadata': type('metadata', (object,), {
            'name': 'SAS4Tool',
            'version': prog_version,
            'author': prog_author,
            'description': prog_desc,
            'long_description': prog_desc,
        }),
        'manifest': None,
        'uac_admin': False,
        'excludes': None,
        'includes': None,
        'packages': None,
        'replace_paths': None,
        'compress': True,
        'optimize': 0,
        'target_dir': build_dir,
        'bin_includes': None,
        'bin_excludes': None,
        'bin_path_includes': None,
        'bin_path_excludes': None,
        'include_files': [
            kwargs['cfg_config'],
            kwargs['cfg_items'],
            kwargs['cfg_license'],
        ],
        'zip_includes': [],
        'zip_include_packages': None,
        'zip_exclude_packages': "*",
        'silent': False,
        'include_msvcr': True,
    }
    executables = [
        Executable(
            args['script'],
            args['init_script'],
            args['base_name'],
            args['target_name'],
            args['icon'],
            args['shortcut_name'],
            args['shortcut_dir'],
            args['copyright'],
            args['trademarks'],
            args['manifest'],
            args['uac_admin'],
        )
    ]
    freezer: Freezer = Freezer(
        executables,
        excludes=args['excludes'],
        includes=args['includes'],
        packages=args['packages'],
        replace_paths=args['replace_paths'],
        compress=args['compress'],
        optimize=args['optimize'],
        path=None,
        target_dir=args['target_dir'],
        bin_includes=args['bin_includes'],
        bin_excludes=args['bin_excludes'],
        bin_path_includes=args['bin_path_includes'],
        bin_path_excludes=args['bin_path_excludes'],
        include_files=args['include_files'],
        zip_includes=args['zip_includes'],
        zip_include_packages=args['zip_include_packages'],
        zip_exclude_packages=args['zip_exclude_packages'],
        silent=args['silent'],
        include_msvcr=args['include_msvcr'],
        metadata=args['metadata'],
    )
    freezer.freeze()
    check_outpath( build_dir, filename )
    output_path = (prog_out_dir / f'{prog_out_filename}.zip')
    zipper( ['--create', f'{output_path}', f'{build_dir}',] )
    output_path = check_outpath( prog_out_dir, prog_out_filename, '.zip' )
    kwargs['prog_out_path'] = output_path
